<template>
  <div class="video-view">
    <div ref="videoRef"></div>
  </div>
</template>

<script setup lang="ts">
import 'xgplayer/dist/index.min.css';

import { nextTick, onUnmounted, PropType, ref, watch } from 'vue';
import Player, { IPlayerOptions } from 'xgplayer';
import FlvPlayer from 'xgplayer-flv';

const props = defineProps({
  url: Object as PropType<any>,
});

const emits = defineEmits([
  'play',
  'pause',
  'ended',
  'error',
  'waiting',
  'canplay',
  'requestFullscreen',
  'exitFullscreen',
  'requestCssFullscreen',
  'exitCssFullscreen',
  'ready',
  'complete',
  'destroy',
  'progress',
  'info',
]);

let player: Player = {} as Player;
const videoRef = ref<HTMLDivElement>();

const flvOptions: IPlayerOptions = {
  el: null,
  url: '',
  width: '100%',
  height: '100%',
  lang: 'zh-cn',
  volume: 0,
  autoplay: true,
  fitVideoSize: 'fixed',
  controls: false,
  // plugins: [FlvJsPlayer],
  plugins: [FlvPlayer],
  isLive: true,
  videoFillMode: 'fill',
  // preloadTime: 30 预加载时长(秒)
  // minCachedTime: 5 当前播放时间距离已缓存资源片段结束点剩多长时间时开始请求新片段(秒)
  // cors: true 请求是否跨域
};

watch(
  () => props.url,
  async (url) => {
    await nextTick();
    flvOptions.url = url;
    flvOptions.el = videoRef.value;
    init();
  },
  { immediate: true },
);

// 初始化player
const init = () => {
  player = new Player({ ...flvOptions });
  setPlayerEvent();
};

// 设置player事件
const setPlayerEvent = () => {
  if (!player) return;
  player.on('play', playEvent);
  player.on('pause', pauseEvent);
  player.on('ended', endedEvent);
  player.on('error', errorEvent);
  player.on('waiting', waitingEvent);
  player.on('canplay', canplayEvent);
  player.on('requestFullscreen', requestFullscreenEvent);
  player.on('exitFullscreen', exitFullscreenEvent);
  player.on('requestCssFullscreen', requestCssFullscreenEvent);
  player.on('exitCssFullscreen', exitCssFullscreenEvent);
  player.on('ready', readyEvent);
  player.on('complete', completeEvent);
  player.on('destroy', destroyEvent);
  player.on('progress', progressEvent);
  player.on('statistics_info', infoEvent);
};

// 销毁player事件
const destroyPlayerEvent = () => {
  if (!player) return;
  player.off('play', playEvent);
  player.off('pause', pauseEvent);
  player.off('ended', endedEvent);
  player.off('error', errorEvent);
  player.off('waiting', waitingEvent);
  player.off('canplay', canplayEvent);
  player.off('requestFullscreen', requestFullscreenEvent);
  player.off('exitFullscreen', exitFullscreenEvent);
  player.off('requestCssFullscreen', requestCssFullscreenEvent);
  player.off('exitCssFullscreen', () => exitCssFullscreenEvent);
  player.off('ready', readyEvent);
  player.off('complete', completeEvent);
  player.off('destroy', destroyEvent);
  player.off('progress', progressEvent);
  player.off('statistics_info', infoEvent);
};

onUnmounted(() => {
  destroy();
});

// ============ 事件函数集合 ==============
const playEvent = () => {
  console.log(`地址：${props?.url} ===> 开始播放`);
  emits('play');
};
const pauseEvent = () => {
  console.log(`地址：${props?.url} ===> 暂停`);
  emits('pause');
};
const endedEvent = () => {
  console.log(`地址：${props?.url} ===> 结束`);
  emits('ended');
};
/*
MediaError 对象的 code 属性返回一个数字值，它表示音频/视频的错误状态
1 = MEDIA_ERR_ABORTED - 取回过程被用户中止
2 = MEDIA_ERR_NETWORK - 当下载时发生错误
3 = MEDIA_ERR_DECODE - 当解码时发生错误
4 = MEDIA_ERR_SRC_NOT_SUPPORTED - 不支持音频/视频
*/
const errorEvent = (error: any) => {
  console.log(`地址：${props?.url} ===> 错误:`, error);
  emits('error', error);
};
const waitingEvent = () => {
  console.log(`地址：${props?.url} ===> 等待加载数据`);
  emits('waiting');
};
const canplayEvent = () => {
  console.log(`地址：${props?.url} ===> 视频可以播放`);
  emits('canplay');
};
const requestFullscreenEvent = () => {
  console.log(`地址：${props?.url} ===> 进入全屏`);
  emits('requestFullscreen');
};
const exitFullscreenEvent = () => {
  console.log(`地址：${props?.url} ===> 退出全屏`);
  emits('exitFullscreen');
};
const requestCssFullscreenEvent = () => {
  console.log(`地址：${props?.url} ===> 进入样式全屏`);
  emits('requestCssFullscreen');
};
const exitCssFullscreenEvent = () => {
  console.log(`地址：${props?.url} ===> 退出样式全屏`);
  emits('exitCssFullscreen');
};
const readyEvent = () => {
  console.log(`地址：${props?.url} ===> 实例化完成`);
  emits('ready');
};
const completeEvent = () => {
  console.log(`地址：${props?.url} ===> 创建video视频完成`);
  emits('complete');
};
const destroyEvent = () => {
  console.log(`地址：${props?.url} ===> 销毁示例`);
  emits('destroy');
};
const progressEvent = () => {
  emits('progress');
};
const infoEvent = (res: { decodedFrames: number }) => {
  console.log('infoEvent', res);
  emits('info');
};

const switchURL = (str: string) => {
  player.switchURL(str);
};

const reload = () => {
  player.reload();
};

const pause = () => {
  player.pause();
};

const resetState = () => {
  player.resetState();
};

const destroy = () => {
  if (!player) return;
  player.destroy();
  player = null;
  destroyPlayerEvent();
};

const playNext = (url: string) => {
  player.playNext({ url });
};

defineExpose({ player, init, switchURL, reload, playNext, pause, resetState, destroy });
</script>

<style lang="less" scoped>
.video-view {
  width: 100%;
  height: 100%;

  :deep(.xgplayer-error) {
    background: var(--co-bg-color20);
    color: var(--co-text-color15);
  }
}
</style>
